<template>
  <Cascader
    v-model:value="emitData"
    :options="options"
    :load-data="loadData"
    change-on-select
    @change="handleChange"
    :displayRender="handleRenderDisplay"
  >
    <template #suffixIcon v-if="loading">
      <LoadingOutlined spin />
    </template>
    <template #notFoundContent v-if="loading">
      <span>
        <LoadingOutlined spin class="mr-1" />
        {{ t('component.form.apiSelectNotFound') }}
      </span>
    </template>
  </Cascader>
</template>
<script lang="ts" setup>
  import { ref, unref, watch } from 'vue';
  import { Cascader } from 'ant-design-vue';
  import { get, omit } from 'lodash-es';
  import { LoadingOutlined } from '@ant-design/icons-vue';
  import { useI18n } from '/@/hooks/web/useI18n';
  import { getAreaList } from '/@/api/system/area';

  interface Option {
    value: string;
    label: string;
    loading?: boolean;
    isLeaf?: boolean;
    children?: Option[];
  }

  const props = defineProps({
    value: String,
  });

  const emit = defineEmits(['change', 'defaultChange', 'update:value']);

  const apiData = ref<any[]>([]);
  const options = ref<Option[]>([]);
  const loading = ref<boolean>(false);
  const emitData = ref<any[]>([]);
  const isChange = ref(false);
  const labelField = 'name';
  const valueField = 'id';
  const childrenField = 'children';
  const resultField = 'data';

  const asyncFetchParamKey = 'id';
  const { t } = useI18n();

  watch(
    () => props.value,
    async (val, oldVal) => {
      if (!val && !!oldVal && val !== oldVal) {
        //重置
        emitData.value = [];
        return;
      }
      //选择时不重复请求接口
      if (isChange.value) return;
      await initialFetch();
      if (val) {
        emitData.value = val.split(',');
        if (emitData.value.length > 1) {
          getParentNodes(emitData.value, options.value);
        }
      } else {
        emitData.value = [];
        return;
      }
    },
    {
      immediate: true,
    },
  );

  watch(
    apiData,
    (data) => {
      options.value = generatorOptions(data);
    },
    { deep: true },
  );

  function generatorOptions(options: any[]): Option[] {
    return options.reduce((prev, next: Recordable) => {
      if (next) {
        const value = next[valueField];
        const item = {
          ...omit(next, [labelField, valueField]),
          label: next[labelField],
          value: `${value}`,
          isLeaf: false,
        };
        const children = Reflect.get(next, childrenField);
        if (children) {
          Reflect.set(item, childrenField, generatorOptions(children));
        }
        prev.push(item);
      }
      return prev;
    }, [] as Option[]);
  }

  async function initialFetch() {
    apiData.value = [];
    loading.value = true;
    try {
      const res = await getAreaList({ id: '0' });
      if (Array.isArray(res)) {
        apiData.value = res;
        return;
      }
      if (resultField) {
        apiData.value = get(res, resultField) || [];
      }
    } catch (error) {
      console.warn(error);
    } finally {
      loading.value = false;
    }
  }

  async function loadData(selectedOptions: Option[]) {
    const targetOption = selectedOptions[selectedOptions.length - 1];
    targetOption.loading = true;

    try {
      const res = await getAreaList({
        [asyncFetchParamKey]: Reflect.get(targetOption, 'value'),
      });

      if (Array.isArray(res)) {
        const children = generatorOptions(res);
        targetOption.children = children;
        return;
      }
      if (resultField) {
        const children = generatorOptions(get(res, resultField) || []);
        targetOption.children = children;
      }
    } catch (e) {
      console.error(e);
    } finally {
      targetOption.loading = false;
    }
  }

  //数据回显
  function getParentNodes(ids: any[], tree: any[]) {
    ids.forEach((id) => {
      tree.forEach(async (item: any) => {
        if (item.value === id) {
          item.children = [];
          const res = await getAreaList({ id });
          item.children = res.map((child) => {
            return {
              label: child.name,
              value: child.id,
              isLeaf: false,
            };
          });
          getParentNodes(ids, item.children);
        }
      });
    });
  }

  function handleChange(keys) {
    isChange.value = true;
    if (!keys) {
      emit('change', keys);
      return;
    }
    emit('change', keys.join(','));
    emit('update:value', keys?.join(','));
    emitData.value = props.value === undefined ? keys : emitData.value;
  }

  function handleRenderDisplay({ labels, selectedOptions }) {
    if (unref(emitData).length === selectedOptions.length) {
      return labels.join(` / `);
    }
  }
</script>
